// 版权归Go作者所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 软件包导入器提供对导出数据导入器的访问。
package importer

import (
	"go/build"
	"go/internal/gccgoimporter"
	"go/internal/gcimporter"
	"go/internal/srcimporter"
	"go/token"
	"go/types"
	"io"
	"runtime"
)

// 查找函数返回一个读卡器，以访问给定导入路径的
// 的包数据，如果找不到匹配的包，则返回一个错误。
type Lookup func(path string) (io.ReadCloser, error)

// ForCompiler为编译器“gc”和“gccgo”返回一个导入器，用于从已安装的软件包导入
// ，或直接从源代码导入
// ，如果编译器参数为“source”。在这种情况下，如果导出的API没有完全在纯Go源代码中定义，则导入可能会失败（如果包API依赖于cgo定义的实体，则类型
// 检查器将无法访问这些实体）。
// 
// 每次生成的导入程序需要
// 解析导入路径时，都会调用查找函数。在这种模式下，导入程序只能用规范的导入路径（不是相对或绝对路径）调用
// 导入程序；
// 假定导入程序的客户正在对规范导入路径进行转换。
// 
// 必须提供查找功能，才能进行正确的模块感知操作。
// 已弃用：如果查找为零，为了向后兼容，导入程序
// 将尝试在$GOPATH工作区中解析导入。
func ForCompiler(fset *token.FileSet, compiler string, lookup Lookup) types.Importer {
	switch compiler {
	case "gc":
		return &gcimports{
			fset:     fset,
			packages: make(map[string]*types.Package),
			lookup:   lookup,
		}

	case "gccgo":
		var inst gccgoimporter.GccgoInstallation
		if err := inst.InitFromDriver("gccgo"); err != nil {
			return nil
		}
		return &gccgoimports{
			packages: make(map[string]*types.Package),
			importer: inst.GetImporter(nil, nil),
			lookup:   lookup,
		}

	case "source":
		if lookup != nil {
			panic("source importer for custom import path lookup not supported (issue #13847).")
		}

		return srcimporter.New(&build.Default, fset, make(map[string]*types.Package))
	}

	// 编译器不支持
	return nil
}

// 用于使用新文件集调用编译器。
// 
// 已弃用：用于编译器，它使用导入程序创建的对象的位置填充文件集
// 。
func For(compiler string, lookup Lookup) types.Importer {
	return ForCompiler(token.NewFileSet(), compiler, lookup)
}

// Default返回编译运行二进制文件的编译器的导入程序。
// 如果可用，结果将实现类型。进口商品。
func Default() types.Importer {
	return For(runtime.Compiler, nil)
}

// gc进口商

type gcimports struct {
	fset     *token.FileSet
	packages map[string]*types.Package
	lookup   Lookup
}

func (m *gcimports) Import(path string) (*types.Package, error) {
	return m.ImportFrom(path, "" /* no vendoring */, 0)
}

func (m *gcimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) {
	if mode != 0 {
		panic("mode must be 0")
	}
	return gcimporter.Import(m.fset, m.packages, path, srcDir, m.lookup)
}

// gccgo进口商

type gccgoimports struct {
	packages map[string]*types.Package
	importer gccgoimporter.Importer
	lookup   Lookup
}

func (m *gccgoimports) Import(path string) (*types.Package, error) {
	return m.ImportFrom(path, "" /* no vendoring */, 0)
}

func (m *gccgoimports) ImportFrom(path, srcDir string, mode types.ImportMode) (*types.Package, error) {
	if mode != 0 {
		panic("mode must be 0")
	}
	return m.importer(m.packages, path, srcDir, m.lookup)
}
